/****************************************************************************
 * Copyright 2010 Huascar A. Sanchez                                        *
 *                                                                          *
 * Licensed under the Apache License, Version 2.0 (the "License");          *
 * you may not use this file except in compliance with the License.         *
 * You may obtain a copy of the License at                                  *
 *                                                                          *
 *     http://www.apache.org/licenses/LICENSE-2.0                           *
 *                                                                          *
 * Unless required by applicable law or agreed to in writing, software      *
 * distributed under the License is distributed on an "AS IS" BASIS,        *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
 * See the License for the specific language governing permissions and      *
 * limitations under the License.                                           *
 ****************************************************************************/
package com.gotobject.greatq;

import com.gotobject.filter.internal.ToStrings;
import org.jiql.jdbc.ResultSet;
import org.jiql.jdbc.Statement;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import static com.gotobject.filter.internal.Pair.of;
import static com.gotobject.filter.internal.ToStrings.str;

/**
 * @author huascar.sanchez@gmail.com (Huascar A. Sanchez)
 */
class SingleQueryImpl implements SingleQuery {
    private final String                        key;
    private final Statement                     internalStatement;
    private final AtomicBoolean                 isExecuted;
    private final AtomicReference<ResultSet>    result;
    private final String                        sql;

    public SingleQueryImpl(QueryServiceImpl oracleImpl, String key, String sql) throws SQLException {
        isExecuted          = new AtomicBoolean(false);
        result              = new AtomicReference<ResultSet>();
        this.sql            = sql;
        this.key            = key;
        internalStatement   = createStatement(oracleImpl.getSharedConnection());
    }

    private static Statement createStatement(Connection conn) throws SQLException {
        return (Statement) conn.createStatement();
    }


    private void ensureIsNotBatch() throws IllegalStateException {
        if(inBatchMode()) throw new IllegalStateException("error:in batch mode");
    }


    private ResultSet execute() throws SQLException {
        ensureIsNotBatch();
        return getInternalStatement().executeQuery(sql);
    }

    Statement getInternalStatement(){
        return internalStatement;
    }

    @Override
    public String getTag() {
        return key;
    }

    @Override
    public String getSql() {
        ensureIsNotBatch();
        return sql;
    }

    @Override
    public ResultSet runAndGet() throws SQLException {
        if(!isExecuted()){
            result.compareAndSet(result.get(), execute());
            isExecuted.set(!isExecuted.get());
        } else {
            return result.get();
        }
        return result.get();
    }

    @Override
    public boolean inBatchMode(){
        return false;
    }

    public boolean isExecuted(){
        return isExecuted.get();
    }


    @Override
    public String toString() {
        return ToStrings.toString(
                this,
                of("key", getTag()),
                of("sql", getSql()),
                of("isExecuted", str(isExecuted()))
        );
    }
}
